package com.atguigu.gulimall.product.thread;

import java.util.concurrent.*;

/**
 * 异步&线程池复习
 *
 * @Author 胡菜鸡
 * @Create 2022-01-12-14:17
 */
public class ThreadTest {

    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws Exception {
//        initThread();
//        createThreadPool();
//        createSyncObject01();
//        createSyncObject02();
//        serialization();
//        taskCombination01();
//        taskCombination02();
        multiTaskCombination();
    }

    /**
     * 初始化线程的4种方法：
     * -    1.继承 Thread
     * -        Thread01 thread = new Thread01();
     * -        thread.start();
     * -
     * -    2.实现 Runnable 接口
     * -        Runnable01 thread = new Runnable01();
     * -        new Thread(thread).start();
     * -
     * -    3.实现 Callable 接口 + FutureTask （可以拿到返回结果，可以处理异常）
     * -        FutureTask<Object> futureTask = new FutureTask<>(new Callable01());
     * -        new Thread(futureTask).start();
     * -
     * -    4.线程池（有资源控制的效果 -> 性能稳定）
     * -        降低资源消耗、提高响应速度、提高线程的可管理性。
     * -        若使用前三种，每次任务到来都会创建一个线程，无线叠加容易导致系统资源崩溃。
     *
     * @author 胡菜鸡
     * @date 2022/1/12 14:19
     */
    public static void initThread() throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        // get()：等待整个线程执行完成，获取返回结果
        Integer integer = futureTask.get();
        System.out.println("main....end...." + integer);
    }

    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }
    }

    /**
     * 创建线程池的方法 & 线程池基本概念
     *
     * @author 胡菜鸡
     * @date 2022/1/12 14:44
     */
    public static void createThreadPool() {
        /*
            线程池的 7 大参数：
                corePoolSize：核心线程【一直存在，除非allowCoreThreadTimeOut】（准备就绪的线程数量，等待执行异步任务）
                maximumPoolSize：最多存储的线程数【控制资源的作用】
                keepAliveTime：线程存活时间【当前线程数 > 核心线程数 ==> 释放线程】
                unit：时间单位【时、分、秒等】
                workQueue：阻塞队列【多余任务会放入队列中】
                threadFactory：线程创建工厂
                handler：当队列满时，处理多余任务的方式【拒绝策略】

            流程：
                1.线程池创建，准备好core【核心线程数】，准备接受任务
                2.core满了，新来的任务会放入阻塞队列中，空闲的core自动去队列中获取任务执行
                3.阻塞队列满了，开启新线程执行，最多只能开到max指定的数量
                4.max满了，使用RejectedExecutionHandler拒绝策略拒绝任务
                5.max都执行完成，有很多空闲，则在keepAliveTime时间后释放线程至core数量
         */
        new ThreadPoolExecutor(
                10,                             //核心线程
                200,                        //最大线程数
                20,                            //线程存活时间
                TimeUnit.SECONDS,                           //时间单位（秒）
                new LinkedBlockingQueue<>(10000),   //阻塞队列（链表）
                Executors.defaultThreadFactory(),           //线程创建工程（默认）
                new ThreadPoolExecutor.AbortPolicy());      //拒绝策略（丢弃新任务）

        /*
            线程池的类型：
         */
//        Executors.newCachedThreadPool();              //带缓存，core为0，都可回收
//        Executors.newFixedThreadPool(10);             //固定大小，core=max，都不可回收
//        Executors.newScheduledThreadPool(20);         //定时任务
//        Executors.newSingleThreadExecutor();          //单任务，core=max=1
    }

    /**
     * 创建异步对象（一）：CompletableFuture 基本使用
     * -    public CompletableFuture<void> runAsync(Runnable runnable, [Executor executor])
     * -    public <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, [Executor executor])
     *
     * @author 胡菜鸡
     * @date 2022/1/12 15:11
     */
    public static void createSyncObject01() throws ExecutionException, InterruptedException {
        System.out.println("start01....");
        CompletableFuture<Void> future01 = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
        }, executor);
        System.out.println("end....");

        System.out.println("start02....");
        CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor);
        System.out.println("end...." + future02.get());
    }

    /**
     * 创建异步对象（二）：CompletableFuture 任务完成后的回调方法和回调的异常处理
     * -    回调：
     * -        public CompletableFuture<T> whenComplete(BiConsumer< ? super T,? super Throwable> action)
     * -        public CompletableFuture<T> whenCompleteAsync(BiConsumer< ? super T,? super Throwable> action, [Executor executor])
     * -
     * -    异常处理：
     * -        public CompletableFuture<T> exceptionally(Function,Throwable,? extends T> fn)
     * -        public <U> CompletableFuture<U> handle(BiFunction< ? super T, Throwable, ? extends U> fn)
     *
     * @author 胡菜鸡
     * @date 2022/1/12 15:11
     */
    public static void createSyncObject02() throws ExecutionException, InterruptedException {
        System.out.println("start...");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).whenCompleteAsync((response, exception) -> {
            //可以成功感知到异常信息，但无法修改返回数据
            System.out.println("异步结果完成了...结果是：" + response + "；异常是：" + exception);
        })/*.exceptionally((throwable) -> {
            System.out.println("出现了异常");
            //感知异常，同时返回默认值（如字符串转整数失败，则可以赋值一个默认值）
            return 10;
        })*/.handle((response, exception) -> {
            if (response != null) {
                return response * 2;
            }
            if (exception != null) {
                return 10;
            }
            return 0;
        });
        System.out.println("end..." + future.get());
    }

    /**
     * 线程串行化方法：thenApply、thenAccept、thenRun
     * -    1.thenRun：不能获取到上一步的执行结果
     * -        public CompletableFuture<Void> thenRun(Runnable action)
     * -        public CompletableFuture<Void> thenRunAsync(Runnable action, [Executor executor])
     * -
     * -    2.thenAccept：能接收上一步的执行结果，但无返回值
     * -        public CompletionStage<Void> thenAccept(Consumer< ? super T> action)
     * -        public CompletionStage<Void> thenAcceptAsync(Consumer< ? super T> action, [Executor executor])
     * -
     * -    3.thenApply：能接收上一步的执行结果，且有返回值
     * -        public <U> CompletableFuture<U> thenApply(Function< ? super T,? extends U> fn)
     * -        public <U> CompletableFuture<U> thenApplyAsync(Function< ? super T,? extends U> fn, [Executor executor])
     *
     * @author 胡菜鸡
     * @date 2022/1/12 15:11
     */
    public static void serialization() throws ExecutionException, InterruptedException {
        System.out.println("start...");
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).thenApplyAsync((response) -> {
            System.out.println("任务2启动了" + response);
            return response * 2 + "haha";
        });
        System.out.println("end..." + future.get());
    }

    /**
     * 两任务组合（一）：任务都完成时才开始执行
     * -    1.runAfterBoth：无接收，无返回值
     * -        public CompletableFuture<Void> runAfterBoth(CompletionStage< ?> other, Runnable action)
     * -        public CompletableFuture<Void> runAfterBothAsync(CompletionStage< ?> other, Runnable action, [Executor executor])
     * -
     * -    2.thenAcceptBoth：有接收，无返回值
     * -        public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage< ? extends U> other,BiConsumer< ? super T, ? super U> action)
     * -        public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage< ? extends U> other, BiConsumer< ? super T, ? super U> action, [Executor executor])
     * -
     * -    3.thenCombine：有接收，有返回值
     * -        public <U,V> CompletableFuture<V> thenCombine(CompletionStage< ? extends U> other, BiFunction< ? super T,? super U,? extends V> fn)
     * -        public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage< ? extends U> other, BiFunction< ? super T,? super U,? extends V> fn, [Executor executor])
     *
     * @author 胡菜鸡
     * @date 2022/1/12 15:11
     */
    public static void taskCombination01() throws ExecutionException, InterruptedException {
        System.out.println("start...");
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一开始：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: " + i);
            return i;
        }, executor);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二开始：" + Thread.currentThread().getId());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务二结束");
            return "hello";
        }, executor);

        //任务一、二都完成时，任务三才会开始
        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
            System.out.println("任务三开始...之前的结果：" + f1 + ":" + f2);
            return f1 + ":" + f2;
        }, executor);
        System.out.println("end..." + future.get());
    }

    /**
     * 两任务组合（二）：其中一个任务完成就开始执行
     * -    1.runAfterBoth：无接收，无返回值
     * -        public CompletableFuture<Void> runAfterEither(CompletionStage< ?> other, Runnable action)
     * -        public CompletableFuture<Void> runAfterEitherAsync(CompletionStage< ?> other, Runnable action, [Executor executor])
     * -
     * -    2.thenAcceptBoth：有接收，无返回值
     * -        public <U> CompletableFuture<Void> acceptEither(CompletionStage< ? extends U> other,BiConsumer< ? super T, ? super U> action)
     * -        public <U> CompletableFuture<Void> acceptEitherAsync(CompletionStage< ? extends U> other, BiConsumer< ? super T, ? super U> action, [Executor executor])
     * -
     * -    3.thenCombine：有接收，有返回值
     * -        public <U,V> CompletableFuture<V> applyToEither(CompletionStage< ? extends U> other, BiFunction< ? super T,? super U,? extends V> fn)
     * -        public <U,V> CompletableFuture<V> applyToEitherAsync(CompletionStage< ? extends U> other, BiFunction< ? super T,? super U,? extends V> fn, [Executor executor])
     *
     * @author 胡菜鸡
     * @date 2022/1/12 15:11
     */
    public static void taskCombination02() throws ExecutionException, InterruptedException {
        System.out.println("start...");
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一开始：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: " + i);
            return i;
        }, executor);

        CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二开始：" + Thread.currentThread().getId());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("任务二结束");
            return 1;
        }, executor);

        //任务一、二都完成时，任务三才会开始
        CompletableFuture<Integer> future = future01.applyToEitherAsync(future02, res -> {
            System.out.println("任务三开始...之前的结果：" + res);
            return res;
        }, executor);
        System.out.println("end..." + future.get());
    }

    /**
     * 多任务组合：
     * -    public static CompletableFuture<Void> allOf(CompletableFuture< ?>... cfs)
     * -    public static CompletableFuture<Object> anyOf(CompletableFuture< ?>... cfs)
     * @author 胡菜鸡
     * @date 2022/1/12 17:41
     */
    public static void multiTaskCombination() throws ExecutionException, InterruptedException {
        System.out.println("start...");
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        }, executor);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("查询商品的属性信息");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "黑色，8+256";
        }, executor);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为";
        }, executor);

        CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//        CompletableFuture<Object> future = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        future.get();       //等待 所有结果/其中之一 完成
        System.out.println("end...");



    }
}
